package com.qqbb.gateway.loadbalancer;

import com.qqbb.common.core.utils.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.*;
import org.springframework.cloud.loadbalancer.core.*;
import org.springframework.http.HttpHeaders;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author fqq
 */
public class GrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    final String defaultVersion;
    final String serverId;
    private static final Log log = LogFactory.getLog(GrayLoadBalancer.class);
    ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    public GrayLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String defaultVersion, String serverId) {
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        this.defaultVersion = defaultVersion;
        this.serverId = serverId;
    }


    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        RequestDataContext requestData = (RequestDataContext) request.getContext();
        HttpHeaders httpHeaders = requestData.getClientRequest().getHeaders();
        String version = httpHeaders.getFirst("version");
        //没传的时候默认选中服务器版本
        if (StringUtils.isEmpty(version) || "undefined".equals(version)) {
            version = defaultVersion;
        }
        ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        String finalVersion = version;
        return supplier.get(request).next().map((serviceInstances) -> {
            return this.processInstanceResponse(supplier, serviceInstances, finalVersion);
        });
    }

    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances, String version) {
        Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances, version);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
        }

        return serviceInstanceResponse;
    }

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, String version) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + this.serverId);
            }
            return new EmptyResponse();
        } else {
            List<ServiceInstance> instanceList = instances.stream()
                    .filter(stance->version.equals(stance.getMetadata().get("version"))).collect(Collectors.toList());
            ServiceInstance serviceInstance;
            //没找到
            if (instanceList.isEmpty()) {
                //找服务器版本尝试
                List<ServiceInstance> defaultList = instances.stream()
                        .filter(stance->defaultVersion.equals(stance.getMetadata().get("version"))).collect(Collectors.toList());
                if (defaultList.isEmpty()) {
                    //服务器版本也不存在
                    if (log.isWarnEnabled()) {
                        log.warn("No servers available for service: " + this.serverId);
                    }
                    return new EmptyResponse();
                }
                //服务器实例存在
                serviceInstance = defaultList.get(0);
            }else{
                //找到指定版本实例
                serviceInstance = instanceList.get(0);
            }
            return new DefaultResponse(serviceInstance);
        }
    }
}
